# Maze.py: maze system for Graphaze
# Written by Victor Luna Freire - victorclf@live.com
# Copyright (c) Victor Luna Freire. All rights reserved.
# Monday, November 02, 2009 1:59:29 AM
# Python 2.6.2

import pygame

import Defines
import Mazeobjects
import MazePlayerAI
import Renderer
import Shared

class MazeClass:
    def __init__(self):
        #self.builder = None
        #self.builder_maze = None
        #self.width = None
        #self.height = None
        
        #self.solver = None
        #self.solver_maze = None
        #self.player_ai = None
            
        self.grid_surface_outdated = True
        self.grid_surface = None
        self.grid_scale = 0
        
        self.CellColor = {}
        self.CellColor['0'] = (0, 0, 0)
        self.CellColor['1'] = (0, 0, 255)
        self.CellColor[chr(Mazeobjects.Cell.UNTOUCHED)] = (0, 0, 0)
        self.CellColor[chr(Mazeobjects.Cell.FRONTIER)] = (140, 140, 140)
        self.CellColor[chr(Mazeobjects.Cell.ADDED)] = (255, 255, 255)
        self.CellColor[chr(Mazeobjects.Cell.IGNORED)] = (0, 0, 255)
        self.CellColor[chr(Mazeobjects.Cell.EXIT)] = (0, 255, 0)
        
    
    def new_maze(self, cell_width, cell_height):
        ''' Start the creation of a new maze. '''
                
        self.builder = Mazeobjects.BuilderPrim(cell_width, cell_height)
        self.update_maze_rep()
        self.width = len(self.builder_maze[0])
        self.height = len(self.builder_maze)
        self.grid_surface = None #reset grid surface
        
    
    def start_solving(self, player):
        maze = self.builder.get_maze()
        self.solver = Mazeobjects.SolverDFS(maze, Mazeobjects.Point(*Renderer.togrid(player.x, player.y)), Mazeobjects.Point(len(maze[0]) - 2, len(maze) - 2))
        self.player_ai = MazePlayerAI.MazePlayerAI(player)
        self.backtracking = False
    
    
    def solver_next_step(self, mult_factor):
        while 1:
            is_done = self.solver.is_done()
            is_moving = self.player_ai.main(mult_factor)
            if is_moving or is_done: break
            
            # Get new destination cell
            self.solver.next_step()
            self.update_solver_rep()
            pos = self.solver.get_cursor()
            self.backtracking = self.solver.backtracking()
            self.player_ai.set_destination(Shared.tounit((pos.x, pos.y)), self.backtracking)
                                    
        return is_moving or (not is_done)
        
    
    def solver_all_steps(self):
        ''' Finish solving the maze. '''
        self.solver.all_steps()
        self.update_solver_rep()
        finalpos = self.solver.get_cursor()
        self.player_ai.teleport(Shared.gridcenter(Shared.tounit((finalpos.x, finalpos.y))))
                
    
    def update_maze_rep(self):
        ''' Updates the maze representation. '''
        self.grid_surface_outdated = True
        self.builder_maze = self.builder.get_maze()
        
    
    def update_solver_rep(self):
        ''' Updates the solver representation. '''
        self.solver_maze = self.solver.get_maze()
    
    
    def adjust_grid_scale(self):
        ''' Calculate the appropriate scale for the grid surface. '''
        
        horizontal_scale = float(Defines.SCREEN_WIDTH) / (self.width * Defines.CUBE_SIZE)
        vertical_scale = float(Defines.SCREEN_HEIGHT) / (self.height * Defines.CUBE_SIZE)
        self.grid_scale = min((horizontal_scale, vertical_scale))
    
    
    def get_maze_copy(self):
        mazecopy = []
        for i in xrange(self.height): mazecopy.append(['0'] * self.width)
        
        for x in xrange(self.width):
            for y in xrange(self.height):
                mazecopy[y][x] = self.builder_maze[y][x]
        
        return mazecopy
    
    
    def create_grid_surface(self):
        ''' Create a new grid surface. '''
        
        self.adjust_grid_scale()
        self.grid_surface = pygame.surface.Surface((Defines.CUBE_SIZE * self.grid_scale * self.width,
                                                    Defines.CUBE_SIZE * self.grid_scale * self.height)).convert()
    
    def builder_is_done(self):
        return self.builder.is_done()
    
    
    def builder_next_step(self):
        ''' Perform next step in the builder. '''
        
        done = self.builder.next_step()
        self.update_maze_rep()
        return done
        
    def builder_finish(self):
        ''' Perform next step in the builder. '''
        
        self.builder.all_steps()
        self.update_maze_rep()
    
            
    def create_builder_grid(self):
        ''' Creates a 2D grid of the builder current maze. '''
        if not self.grid_surface: self.create_grid_surface()
        
        #print "create_builder_grid"
        #print "width:", self.width
        #print "height:", self.height
        #print "grid_scale:", self.grid_scale
        #for x in xrange(self.width):
        #    for y in xrange(self.height):
        #        print self.builder_maze[y][x],
        #    print
                
        self.grid_surface.fill((0,0,0))  #clears grid_surface
        for x in xrange(self.width):
            for y in xrange(self.height):
                newrect = pygame.rect.Rect(x * Defines.CUBE_SIZE * self.grid_scale,
                                           y * Defines.CUBE_SIZE * self.grid_scale,
                                           Defines.CUBE_SIZE * self.grid_scale, Defines.CUBE_SIZE * self.grid_scale)
                # Draw empty square
                #pygame.draw.rect(self.grid_surface, (55,55,55), newrect, 1)
                
                boxrect = pygame.rect.Rect(x * Defines.CUBE_SIZE * self.grid_scale,
                                               y * Defines.CUBE_SIZE * self.grid_scale,
                                               Defines.CUBE_SIZE * self.grid_scale,
                                               Defines.CUBE_SIZE * self.grid_scale)
                
                # Fill square
                self.grid_surface.fill(self.CellColor[self.builder_maze[y][x]], boxrect)
        
        self.grid_surface_outdated = False
                  
    
    def get_grid_surface(self):
        if self.grid_surface_outdated: self.create_builder_grid()
        return self.grid_surface
        
        
    


Maze = MazeClass()
